using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;

namespace Fantasy.SourceGenerator.Generators
{
    /// <summary>
    /// 程序集初始化器生成器
    /// 为每个 Fantasy 项目生成 ModuleInitializer，在程序集加载时自动注册到框架
    /// 支持 Native AOT，无需运行时反射
    /// </summary>
    [Generator]
    public class AssemblyInitializerGenerator : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            // 获取编译信息
            var compilationProvider = context.CompilationProvider;
            // 注册源代码输出
            context.RegisterSourceOutput(compilationProvider, (spc, compilation) =>
            {
                if (CompilationHelper.IsSourceGeneratorDisabled(compilation))
                {
                    return;
                }
                
                if (!CompilationHelper.HasFantasyDefine(compilation))
                {
                    // 不是 Fantasy 框架项目，跳过代码生成
                    return;
                }
                
                if (compilation.GetTypeByMetadataName("Fantasy.Assembly.IEntitySystemRegistrar") == null)
                {
                    return;
                }
                
                GenerateModuleInitializer(spc, compilation);
            });
        }

        private static void GenerateModuleInitializer(
            SourceProductionContext context,
            Compilation compilation)
        {
            var targetPlatform = CompilationHelper.GetTargetPlatform(compilation);
            var markerClassName = compilation.GetAssemblyName("AssemblyInitializer", out var assemblyName,
                out var replaceAssemblyName);
            var builder = new SourceCodeBuilder();
            // 添加文件头
            builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
            // 添加 using
            switch (targetPlatform)
            {
                case 1: // Server (.NET)
                {
                    builder.AddUsings(
                        "System",
                        "System.Runtime.CompilerServices"
                    );
                    break;
                }
                case 2: // Unity
                {
                    builder.AddUsings(
                        "System",
                        "UnityEngine"
                    );
                    break;
                }
                case 3: // Unity 但没有使用Unity相关的程序集
                {
                    builder.AddUsings(
                        "System",
                        "System.Runtime.CompilerServices"
                    );
                    break;
                }
            }
            
            builder.AppendLine();
            // 开始命名空间
            builder.BeginDefaultNamespace();
            // 添加类注释
            builder.AddXmlComment($"Auto-generated assembly initializer for {assemblyName}");
            builder.AddXmlComment("This class is automatically invoked when the assembly is loaded via ModuleInitializer");
            // 开始类定义
            builder.BeginClass(markerClassName, "public static");
            // 添加字段
            builder.AppendLine("private static bool _initialized;");
            builder.AppendLine("private static long _assemblyManifestId;");
            builder.AppendLine();
            // 生成 ModuleInitializer 方法
            GenerateInitializeMethod(builder, markerClassName, replaceAssemblyName, targetPlatform);
            // 生成卸载方法
            GenerateUnloadMethod(builder, targetPlatform);
            // 结束 AssemblyInitializer 类
            builder.EndClass();
            builder.AppendLine();
            // 结束命名空间
            builder.EndNamespace();
            // 输出源代码
            context.AddSource($"{markerClassName}.g.cs", builder.ToString());
        }

        private static void GenerateInitializeMethod(SourceCodeBuilder builder, string markerClassName, string replaceAssemblyName, int targetPlatform)
        {
            switch (targetPlatform)
            {
                case 1:     // Server (.NET)
                {
                    builder.AddXmlComment("Module initializer - automatically called when assembly is loaded");
                    builder.AppendLine("[ModuleInitializer]");
                    builder.BeginMethod("public static void Initialize()");
                    break;
                }
                case 2:     // Unity
                {
                    builder.AddXmlComment(
                        "Unity runtime initializer - automatically called when entering play mode or on app start");
                    builder.AppendLine("[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]");
                    builder.BeginMethod("public static void Initialize()");
                    break;
                }
                case 3:     // Unity 但没有使用Unity相关的程序集
                {
                    builder.AddXmlComment("Module initializer - automatically called when assembly is loaded");
                    builder.BeginMethod("public static void Initialize()");
                    break;
                }
            }

            // 防止重复初始化
            builder.AppendLine("if (_initialized)");
            builder.OpenBrace();
            builder.AppendLine("return;");
            builder.CloseBrace();
            builder.AppendLine();
            builder.AppendLine("_initialized = true;");
            builder.AppendLine();

            // 获取程序集并计算唯一标识
            builder.AddComment("Get assembly and calculate manifest ID");
            builder.AppendLine($"var assembly = typeof({markerClassName}).Assembly;");
            builder.AppendLine(
                $"_assemblyManifestId = Fantasy.Helper.HashCodeHelper.ComputeHash64(assembly.GetName().Name ?? \"{markerClassName}\");");
            builder.AppendLine();

            // 注册卸载事件（用于热更新支持）
            builder.AddComment("Register auto-unload for collectible AssemblyLoadContext (hot-reload support)");
           
            if (targetPlatform == 2 || targetPlatform == 3)
            {
                builder.AppendLine(
                    "#if !UNITY_EDITOR && !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_WEBGL");
            }

            builder.AppendLine("var loadContext = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(assembly);");
            builder.AppendLine(
                "if (loadContext != null && loadContext != System.Runtime.Loader.AssemblyLoadContext.Default)");
            builder.OpenBrace();
            builder.AppendLine("loadContext.Unloading += OnAssemblyUnloading;");
            builder.CloseBrace();
            
            if (targetPlatform == 2 || targetPlatform == 3)
            {
                builder.AppendLine("#endif");
            }

            builder.AppendLine();

            // 声明所有可能的注册器变量
            builder.AddComment("Declare registrar variables");
            builder.AppendLine("Fantasy.Assembly.INetworkProtocolRegistrar? networkProtocolRegistrar = null;");
            builder.AppendLine("Fantasy.Assembly.IEventSystemRegistrar? eventSystemRegistrar = null;");
            builder.AppendLine("Fantasy.Assembly.IEntitySystemRegistrar? entitySystemRegistrar = null;");
            builder.AppendLine("Fantasy.Assembly.IMessageHandlerResolver? messageHandlerResolverRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.IEntityTypeCollectionRegistrar? entityTypeCollectionRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.IOpCodeRegistrar? opCodeRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.IResponseTypeRegistrar? responseTypeRegistrar = null;");
            builder.AppendLine("#if FANTASY_NET", false);
            builder.AppendLine(
                "Fantasy.Assembly.ISeparateTableRegistrar? separateTableRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.ISphereEventRegistrar? sphereEventRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.IFantasyConfigRegistrar? fantasyConfigRegistrar = null;");
            builder.AppendLine("#endif", false);
            builder.AppendLine(
                "Fantasy.Assembly.ICustomInterfaceRegistrar? customInterfaceRegistrar = null;");
            builder.AppendLine(
                "Fantasy.Assembly.IPoolCreatorGenerator? poolCreatorGeneratorRegistrar = null;");
            builder.AppendLine();
            
            // 尝试创建各个注册器（如果存在）replaceAssemblyName
            builder.AddComment("Try to create registrars if they were generated in this assembly");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_NetworkProtocol", "networkProtocolRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_EventSystem", "eventSystemRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_EntitySystem", "entitySystemRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_MessageHandlerResolver", "messageHandlerResolverRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_EntityTypeCollection", "entityTypeCollectionRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_OpCode", "opCodeRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_ResponseType", "responseTypeRegistrar");
            builder.AppendLine("#if FANTASY_NET", false);
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_SeparateTable", "separateTableRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_SphereEvent", "sphereEventRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_FantasyConfig", "fantasyConfigRegistrar");
            builder.AppendLine("#endif", false);
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_CustomInterface", "customInterfaceRegistrar");
            GenerateTryCreateRegistrar(builder, $"{replaceAssemblyName}_PoolCreatorGenerator", "poolCreatorGeneratorRegistrar");
            
            builder.AppendLine();

            // 注册到框架
            builder.AddComment("Register complete AssemblyManifest to the framework");
            builder.AppendLine("#if FANTASY_NET", false);
            builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Register(");
            builder.Indent();
            builder.AppendLine("_assemblyManifestId,");
            builder.AppendLine("assembly,");
            builder.AppendLine("networkProtocolRegistrar,");
            builder.AppendLine("eventSystemRegistrar,");
            builder.AppendLine("entitySystemRegistrar,");
            builder.AppendLine("messageHandlerResolverRegistrar,");
            builder.AppendLine("entityTypeCollectionRegistrar,");
            builder.AppendLine("separateTableRegistrar,");
            builder.AppendLine("opCodeRegistrar,");
            builder.AppendLine("responseTypeRegistrar,");
            builder.AppendLine("sphereEventRegistrar,");
            builder.AppendLine("customInterfaceRegistrar,");
            builder.AppendLine("fantasyConfigRegistrar,");
            builder.AppendLine("poolCreatorGeneratorRegistrar);");
            builder.Unindent();
            builder.AppendLine("#endif", false);
            builder.AppendLine("#if FANTASY_UNITY", false);
            builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Register(");
            builder.Indent();
            builder.AppendLine("_assemblyManifestId,");
            builder.AppendLine("assembly,");
            builder.AppendLine("networkProtocolRegistrar,");
            builder.AppendLine("eventSystemRegistrar,");
            builder.AppendLine("entitySystemRegistrar,");
            builder.AppendLine("messageHandlerResolverRegistrar,");
            builder.AppendLine("entityTypeCollectionRegistrar,");
            builder.AppendLine("opCodeRegistrar,");
            builder.AppendLine("responseTypeRegistrar,");
            builder.AppendLine("customInterfaceRegistrar,");
            builder.AppendLine("poolCreatorGeneratorRegistrar);");
            builder.Unindent();
            builder.AppendLine("#endif", false);
            builder.EndMethod();
        }

        private static void GenerateUnloadMethod(SourceCodeBuilder builder, int targetPlatform)
        {
            builder.AppendLine();
            builder.AddXmlComment("Called when AssemblyLoadContext is unloading (for hot-reload support)");

            // Unity 环境下，AssemblyLoadContext 仅在非编辑器/非独立平台可用
            if (targetPlatform == 2 || targetPlatform == 3)
            {
                builder.AppendLine(
                    "#if !UNITY_EDITOR && !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_WEBGL");
            }

            builder.BeginMethod("private static void OnAssemblyUnloading(System.Runtime.Loader.AssemblyLoadContext context)");

            builder.AddComment("Unregister from framework");
            builder.AppendLine("if (_assemblyManifestId != 0)");
            builder.OpenBrace();
            builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Unregister(_assemblyManifestId);");
            builder.CloseBrace();

            builder.EndMethod();

            if (targetPlatform == 2 || targetPlatform == 3)
            {
                builder.AppendLine("#endif");
            }
        }

        private static void GenerateTryCreateRegistrar(
            SourceCodeBuilder builder,
            string registrarName,
            string variableName)
        {
            var typeName = $"Fantasy.Generated.{registrarName}Registrar";
            builder.AppendLine($"{variableName} = new {typeName}();");
        }
    }
}
